﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;

namespace CID.Tests.Support
{
    public static class PropertySetter
    {
        private static PropertyInfo GetPropertyInfo<TObject, TProperty>(Expression<Func<TObject, TProperty>> propertyLambda) where TObject : class
        {
            Type type = typeof(TObject);

            MemberExpression memberExpression = propertyLambda.Body as MemberExpression;
            if (memberExpression == null)
                throw new ArgumentException(String.Format("Expression '{0}' refers to a method, not a property.", propertyLambda.ToString()));

            PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
            if (propertyInfo == null)
                throw new ArgumentException(String.Format("Expression '{0}' refers to a field, not a property.", propertyLambda.ToString()));

            if (type != propertyInfo.ReflectedType && !type.IsSubclassOf(propertyInfo.ReflectedType))
                throw new ArgumentException(String.Format("Expresion '{0}' refers to a property that is not from type {1}.", propertyLambda.ToString(), type));

            return propertyInfo;
        }

        public static void SetProperty<TObject, TProperty>(this TObject target, Expression<Func<TObject, TProperty>> propertyLambda, TProperty value) where TObject : class
        {
            var propertyInfo = GetPropertyInfo(propertyLambda);

            propertyInfo.SetValue(target, value, new object[] { });
        }

        public static void ModifyProperty<TObject>(this TObject target, Expression<Func<TObject, string>> propertyLambda) where TObject : class
        {
            var propertyInfo = GetPropertyInfo(propertyLambda);

            string modifiedValue = String.Format("Modified_{0}", propertyInfo.GetValue(target, new object[] { }));
            propertyInfo.SetValue(target, modifiedValue, new object[] { });
        }

        public static void ModifyProperty<TObject>(this TObject target, Expression<Func<TObject, bool>> propertyLambda) where TObject : class
        {
            var propertyInfo = GetPropertyInfo(propertyLambda);

            bool modifiedValue = !(bool)propertyInfo.GetValue(target, new object[] { });
            propertyInfo.SetValue(target, modifiedValue, new object[] { });
        }

    }
}
